package cz.cvut.fel.taskpro.business.manager;

import cz.cvut.fel.taskpro.business.imanager.IUserBusiness;
import cz.cvut.fel.taskpro.business.isupport.IBusinessRuleValidator;
import cz.cvut.fel.taskpro.business.isupport.IMail;
import cz.cvut.fel.taskpro.business.support.BusinessRuleException;
import cz.cvut.fel.taskpro.business.support.TaskProException;
import cz.cvut.fel.taskpro.data.entity.Admin;
import cz.cvut.fel.taskpro.data.entity.GroupTaskPro;
import cz.cvut.fel.taskpro.data.entity.Kantor;
import cz.cvut.fel.taskpro.data.entity.Student;
import cz.cvut.fel.taskpro.data.entity.Subject;
import cz.cvut.fel.taskpro.data.entity.TaskProUser;
import cz.cvut.fel.taskpro.data.entity.Team;
import cz.cvut.fel.taskpro.data.imanager.IUserData;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;
import jxl.JXLException;
import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;
import javax.xml.bind.DatatypeConverter;

/**
 * This class implement #{@link IUserBusiness} interface
 * @author Martin Tomasek
 * @version 1.0 beta
 */
@DeclareRoles({"admin", "kantor", "student"})
@Stateless
public class UserBusiness implements IUserBusiness, Serializable {

    private SecureRandom random = new SecureRandom();
    private final String webAddress = "http://icpc.felk.cvut.cz/SZU-war/";
    private final String webSubject = "TaskPro - registration";
    private final int lenghtOfPassword = 32;
    @Inject
    private IUserData userData;
    @EJB
    private IBusinessRuleValidator validator;
    @EJB
    private IMail mail;

    public UserBusiness() {
    }

    @RolesAllowed("admin")
    @Override
    public List<Student> getStudentsAll() {
        List<Student> mStudents = userData.getAllStudents();
        return mStudents;
    }

    @RolesAllowed("admin")
    @Override
    public List<TaskProUser> readExcel(File fileWithUsers) throws BusinessRuleException, TaskProException {
        List<TaskProUser> users = new ArrayList<TaskProUser>();
        Workbook workbook = null;
        try {
            workbook = Workbook.getWorkbook(fileWithUsers);
            Sheet sheet = workbook.getSheet(0);
            //prvni je slupec druhy je radek
            int radek = 0;
            while (true) {
                sheet.getCell(0, radek).getContents();
                TaskProUser newUser = createUser(sheet.getCell(0, radek).getContents(),
                        sheet.getCell(1, radek).getContents(),
                        sheet.getCell(2, radek).getContents(), sheet.getCell(3, radek).getContents(),
                        sheet.getCell(4, radek).getContents(),
                        sheet.getCell(5, radek).getContents());
                if (newUser == null) {
                    break;
                }
                users.add(newUser);
                radek++;
            }
        } catch (IOException ex) {
            throw new TaskProException(90, "IOException has occured during reading file" + fileWithUsers.getAbsolutePath());
        } catch (BiffException ex) {
            throw new TaskProException(90, "BiffException has occured during reading file" + fileWithUsers.getAbsolutePath());
        } catch (JXLException e) {
            workbook.close();
        } catch (Exception e) {
            workbook.close();
        }
        return users;


    }

    @RolesAllowed("admin")
    private TaskProUser createUser(String login, String password, String name, String surname, String email, String state) {
        TaskProUser newUser = null;
        if (state.equals("student")) {
            newUser = new Student();
        } else if (state.equals("teacher")) {
            newUser = new Kantor();
        } else if (state.equals("admin")) {
            newUser = new Admin();
        } else {
            return null;
        }
        newUser.setLogin(login);
        newUser.setEmail(email);
        newUser.setName(name);
        newUser.setSurname(surname);
        newUser.setPassword(password);
        return newUser;
    }

    @RolesAllowed("admin")
    @Override
    public void addUser(TaskProUser newUser, String state) throws BusinessRuleException, TaskProException {
        validator.validateAdding(newUser);
        TaskProUser newUserToDb = null;
        if (state.equals("student")) {
            newUserToDb = new Student();
        } else if (state.equals("teacher")) {
            newUserToDb = new Kantor();
        } else if (state.equals("admin")) {
            newUserToDb = new Admin();
        }
        newUserToDb.setEmail(newUser.getEmail());
        newUserToDb.setLogin(newUser.getLogin());
        newUserToDb.setName(newUser.getName());
        if (newUser.getPassword().isEmpty()) {
            newUserToDb.setPassword(randomString(lenghtOfPassword));
        } else {
            newUserToDb.setPassword(newUser.getPassword());
        }
        newUserToDb.setSurname(newUser.getSurname());
        mail.notifyAddUser(newUserToDb);
        newUserToDb.setPassword(makeSh256(newUserToDb.getPassword()));
        userData.addUser(newUserToDb);
       
    }

    @RolesAllowed("admin")
    @Override
    public void addUser(List<TaskProUser> users) throws BusinessRuleException, TaskProException {
        
        validator.validateAdding(users);
        List<TaskProUser> usersToAdd=new ArrayList<TaskProUser>();
        Iterator userIt = users.iterator();
        while (userIt.hasNext()) {
            TaskProUser userToAdd = (TaskProUser) userIt.next();
            if (userToAdd.getPassword().isEmpty()) {
                userToAdd.setPassword(randomString(lenghtOfPassword));
            }
            usersToAdd.add(userToAdd);
            userToAdd.setPassword(makeSh256(userToAdd.getPassword()));
            userData.addUser(userToAdd);
        }
        mail.notifyAddUser(usersToAdd);
    }

    @PermitAll
    private String randomString(int length) {
        String randomSt = new BigInteger(130, random).toString(length);
        return randomSt;
    }

    @PermitAll
    private String makeSh256(String toCode)  {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
            messageDigest.update(toCode.getBytes("UTF-8"));
            byte[] codeByte = messageDigest.digest();
            String toReturn=DatatypeConverter.printBase64Binary(codeByte);
            return toReturn;
        } catch (UnsupportedEncodingException ex) {
            return "fjasndkfjdsnakjnfa";
        }
        catch(NoSuchAlgorithmException ex){
           return "fjasndkfjdsnakjnfa"; 
        }
    }


    @RolesAllowed("admin")
    @Override
    public List<TaskProUser> getAllUsers() {
        List<TaskProUser> users = userData.getAllUsers();
        return users;
    }

    @RolesAllowed("admin")
    @Override
    public List<Kantor> getAllKantor() {
        List<Kantor> kantors = userData.getAllKantors();
        return kantors;
    }

    @RolesAllowed("admin")
    @Override
    public List<TaskProUser> readCSV(InputStream fileCSV) throws BusinessRuleException, TaskProException {
        //TO DO check...
        List<TaskProUser> users = new ArrayList<TaskProUser>();
        String radkaCSV;
        String actualString[] = null;
        BufferedReader br = new BufferedReader(new InputStreamReader(fileCSV));
        try {

            while ((radkaCSV = br.readLine()) != null) {
                actualString = radkaCSV.split(";");
                users.add(createUser(actualString[0], actualString[1], actualString[2],
                        actualString[3], actualString[4], actualString[5]));
            }

        } catch (IOException ex) {
            Logger.getLogger(UserBusiness.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception e) {
        }
        return users;

    }

  
    @PermitAll
    @Override
    public TaskProUser findUserByLogin(String login) {
        TaskProUser tempUser = userData.findByLogin(login);
        return tempUser;
    }

   
    @RolesAllowed("admin")
    @Override
    public void removeUser(TaskProUser userToDelete) throws BusinessRuleException {
        validator.validate(userToDelete);
        userData.removeUser(userToDelete);
    }

    
    @PermitAll
    @Override
    public void modifyUser(TaskProUser user, String newPassword) throws BusinessRuleException {
        if (newPassword != null) {
            if (!newPassword.isEmpty()) {
                user.setPassword(newPassword);
                validator.validateModification(user);
                user.setPassword(makeSh256(user.getPassword()));
            } else {
                validator.validateModification(user);
            }
        } else {
            validator.validateModification(user);
        }
        userData.updateUser(user);
    }

    @RolesAllowed({"admin","kantor","student"})
    @Override
    public void resetPassword(TaskProUser user) throws BusinessRuleException, TaskProException {
        validator.validate(user);
        String password = randomString(lenghtOfPassword);
        user.setPassword(makeSh256(password));
        userData.updateUser(user);
        mail.notifyResetPassword(user, password, webAddress);
    }

    @RolesAllowed({"admin","kantor","student"})
    @Override
    public List<Student> getStudenstByKantor(Kantor teacher) {
        return userData.getAllStudentByKantor(teacher);
    }

    @RolesAllowed({"admin","kantor","student"})
    @Override
    public List<Student> getStudentsByGroup(List<GroupTaskPro> groups) {
        return userData.getStudentsByGroup(groups);
    }

    @RolesAllowed({"admin","kantor","student"})
    @Override
    public List<Student> getStudentsByGroup(GroupTaskPro group) throws BusinessRuleException {
        validator.validate(group);
        return userData.getStudentsByGroup(group);
    }

    @RolesAllowed({"admin","kantor","student"})
    @Override
    public List<Student> getStudentsByTeam(List<Team> teams) {
        return userData.getStudentsByTeam(teams);
    }

    @RolesAllowed({"admin","kantor","student"})
    @Override
    public List<Student> getStudentsBySubjectAndKantor(Kantor kantor, Subject subject) throws BusinessRuleException {
        validator.validate(subject);
        validator.validate(kantor);
        return userData.getStudentByContext(kantor, subject);
    }
    @RolesAllowed({"admin","kantor","student"})
    @Override
    public List<Student> getStudentsNotInTeam(GroupTaskPro group) throws BusinessRuleException {
        return userData.getStudentNotInTeam(group);
    }
}